package com.lyrcsoft.spring;

import com.lyrcsoft.spring.beans.annotation.Autowire;
import com.lyrcsoft.spring.beans.factory.BeanNameAware;
import com.lyrcsoft.spring.beans.factory.BeanPostProcessor;
import com.lyrcsoft.spring.beans.factory.InitializingBean;
import com.lyrcsoft.spring.beans.factory.config.BeanDefinition;
import com.lyrcsoft.spring.context.annotation.ComponentScan;
import com.lyrcsoft.spring.context.annotation.Scope;
import com.lyrcsoft.spring.stereotype.Component;
import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class LyrcSoftApplicationContext {


	private Class configClazz = null;
	private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
	private Map<String, Object> singletonObjects = new HashMap<>();
	private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

	public LyrcSoftApplicationContext(Class configClazz) {
		this.configClazz = configClazz;
		// 1、扫描.class文件
		doScan(configClazz);
		// 2、创建单例bean
		for (Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
			String beanName = entry.getKey();
			BeanDefinition beanDefinition = entry.getValue();
			if (beanDefinition.getScope().equals("singleton")) {
				// 放到单例池
				Object bean = createBean(beanName, beanDefinition);
				singletonObjects.put(beanName, bean);
			}
		}
	}

	private Object createBean(String beanName, BeanDefinition beanDefinition) {
		//
		Class<?> clazz = beanDefinition.getType();
		Object instance = null;
		try {
			instance = clazz.getConstructor().newInstance();
			// 依赖注入
			for (Field field : clazz.getDeclaredFields()) {
				if (field.isAnnotationPresent(Autowire.class)) {
					field.setAccessible(true);
					field.set(instance, getBean(field.getName()));
				}
			}
			//
			if(instance instanceof BeanNameAware){
			 ((BeanNameAware) instance).setBeanName(beanName);
			}

			// 初始化前（后置处理器）
			for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
				instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
			}
			// 初始化
			if (instance instanceof InitializingBean) {
				InitializingBean initializingBean = (InitializingBean) instance;
				initializingBean.afterPropertiesSet();
			}
			// 初始化后（后置处理器）
			for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
				instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
			}
		} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
			throw new RuntimeException(e);
		}
		return instance;
	}


	public Object getBean(String beanName) {
		// beanName ---> UserService.class --->
		//
		if (!beanDefinitionMap.containsKey(beanName)) {
			throw new NullPointerException("[" + beanName + "] beanName未找到");
		}
		BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
		// singleton
		if (beanDefinition.getScope().equals("singleton")) {
			// 有可能去拿的时候，bean还没有被创建
			Object singletonBean = singletonObjects.get(beanName);
			if (singletonBean == null) {
				singletonBean = createBean(beanName, beanDefinition);
				singletonObjects.put(beanName, singletonBean);
			}
			return singletonBean;
		}
		// prototype
		else {
			Object prototypeBean = createBean(beanName, beanDefinition);
			return prototypeBean;
		}
	}


	/**
	 * 扫描
	 *
	 * @param configClazz
	 */
	private void doScan(Class<?> configClazz) {
		if (configClazz.isAnnotationPresent(ComponentScan.class)) {
			ComponentScan componentScan = (ComponentScan) configClazz.getAnnotation(ComponentScan.class);
			String path = componentScan.value();
			System.out.println("扫描路径：" + path);
			// target/classes
			ClassLoader classLoader = this.getClass().getClassLoader();
			URL resource = classLoader.getResource(path.replace(".", "/"));
			// 拿到目录
			File file = new File(resource.getFile());
			if (file.isDirectory()) {
				for (File f : file.listFiles()) {
					String absolutePath = f.getAbsolutePath();
					System.out.println(absolutePath);
					absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.lastIndexOf(".class"));
					System.out.println(absolutePath);
					absolutePath = absolutePath.replace("\\", ".");
					System.out.println(absolutePath);
					// 判断文件是否包含了Component注解
					try {
						Class<?> clazz = classLoader.loadClass(absolutePath);
						// 判断这个类是不是一个Bean
						if (clazz.isAnnotationPresent(Component.class)) {
							// 判断这个类是否实现BeanPostProcessor接口
							if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
								// 扫描时 将后置处理器读出来
								BeanPostProcessor postProcessor = (BeanPostProcessor) clazz.getConstructor().newInstance();
								beanPostProcessors.add(postProcessor);
							}
							// 其他非后置处理器的bean
							else {
								Component component = clazz.getAnnotation(Component.class);
								String beanName = component.value();
								if ("".equals(beanName)) {
									beanName = Introspector.decapitalize(clazz.getSimpleName());
								}
								BeanDefinition beanDefinition = new BeanDefinition();
								beanDefinition.setType(clazz);
								System.out.println(clazz);
								if (clazz.isAnnotationPresent(Scope.class)) {
									Scope scope = clazz.getAnnotation(Scope.class);
									beanDefinition.setScope(scope.value());
								} else {
									beanDefinition.setScope("singleton");
								}
								beanDefinitionMap.put(beanName, beanDefinition);
							}
						}
					} catch (ClassNotFoundException | NoSuchMethodException e) {
						throw new RuntimeException(e);
					} catch (InvocationTargetException e) {
						e.printStackTrace();
					} catch (InstantiationException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}
